package org.ysling.litemall.core.service;
/**
 *  Copyright (c) [ysling] [927069313@qq.com]
 *  [litemall-plus] is licensed under Mulan PSL v2.
 *  You can use this software according to the terms and conditions of the Mulan PSL v2.
 *  You may obtain a copy of Mulan PSL v2 at:
 *              http://license.coscl.org.cn/MulanPSL2
 *  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 *  EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 *  MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *  See the Mulan PSL v2 for more details.
 */

import lombok.extern.slf4j.Slf4j;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.ysling.litemall.core.utils.IpUtil;
import org.ysling.litemall.db.domain.LitemallAdmin;
import org.ysling.litemall.db.domain.LitemallLog;
import org.ysling.litemall.core.utils.GlobalWebUtil;
import org.ysling.litemall.db.service.LitemallLogService;

import javax.servlet.http.HttpServletRequest;

/**
 * 这里的日志类型设计成四种（当然开发者需要可以自己扩展）
 * 一般日志：用户觉得需要查看的一般操作日志，建议是默认的日志级别
 * 安全日志：用户安全相关的操作日志，例如登录、删除管理员
 * 订单日志：用户交易相关的操作日志，例如订单发货、退款
 * 其他日志：如果以上三种不合适，可以选择其他日志，建议是优先级最低的日志级别
 * <p>
 * 当然可能很多操作是不需要记录到数据库的，例如编辑商品、编辑广告品之类。
 *
 * @author Ysling
 * @Async 异步处理可防止事务回滚
 */
@Slf4j
@Service
public class ActionLogService {

    public static final  Short LOG_TYPE_GENERAL = 0;
    public static final  Short LOG_TYPE_AUTH = 1;
    public static final  Short LOG_TYPE_ORDER = 2;
    public static final  Short LOG_TYPE_OTHER = 3;

    @Autowired
    private LitemallLogService litemallLogService;

    /**
     * 操作成功
     * 一般日志：用户觉得需要查看的一般操作日志，建议是默认的日志级别
     * @param action 操作动作
     */
    @Async
    public void logGeneralSucceed(String action) {
        logAdmin(LOG_TYPE_GENERAL, action, true, "", "");
    }

    /**
     * 操作成功
     * 一般日志：用户觉得需要查看的一般操作日志，建议是默认的日志级别
     * @param action 操作动作
     * @param result 操作结果
     */
    @Async
    public void logGeneralSucceed(String action, String result) {
        logAdmin(LOG_TYPE_GENERAL, action, true, result, "");
    }

    /**
     * 操作成功
     * 一般日志：用户觉得需要查看的一般操作日志，建议是默认的日志级别
     * @param action 操作动作
     * @param result 操作结果
     * @param comment 操作备注
     */
    @Async
    public void logGeneralSucceed(String action, String result, String comment) {
        logAdmin(LOG_TYPE_GENERAL, action, true, result, comment);
    }

    /**
     * 操作失败
     * 一般日志：用户觉得需要查看的一般操作日志，建议是默认的日志级别
     * @param action 操作动作
     * @param error 操作结果
     */
    @Async
    public void logGeneralFail(String action, String error) {
        logAdmin(LOG_TYPE_GENERAL, action, false, error, "");
    }

    /**
     * 操作失败
     * 一般日志：用户觉得需要查看的一般操作日志，建议是默认的日志级别
     * @param action 操作动作
     * @param error 操作结果
     * @param comment 操作备注
     */
    @Async
    public void logGeneralFail(String action, String error, String comment) {
        logAdmin(LOG_TYPE_GENERAL, action, false, error, comment);
    }

    /**
     * 操作成功
     * 安全日志：用户安全相关的操作日志，例如登录、删除管理员
     * @param action 操作动作
     */
    @Async
    public void logAuthSucceed(String action) {
        logAdmin(LOG_TYPE_AUTH, action, true, "", "");
    }

    /**
     * 操作成功
     * 安全日志：用户安全相关的操作日志，例如登录、删除管理员
     * @param action 操作动作
     * @param result 操作结果
     */
    @Async
    public void logAuthSucceed(String action, String result) {
        logAdmin(LOG_TYPE_AUTH, action, true, result, "");
    }

    /**
     * 操作成功
     * 安全日志：用户安全相关的操作日志，例如登录、删除管理员
     * @param action 操作动作
     * @param error 操作结果
     * @param comment 操作备注
     */
    @Async
    public void logAuthSucceed(String action, String error, String comment) {
        logAdmin(LOG_TYPE_GENERAL, action, false, error, comment);
    }

    /**
     * 操作失败
     * 安全日志：用户安全相关的操作日志，例如登录、删除管理员
     * @param action 操作动作
     * @param error 操作结果
     */
    @Async
    public void logAuthFail(String action, String error) {
        logAdmin(LOG_TYPE_AUTH, action, false, error, "");
    }

    /**
     * 操作失败
     * 安全日志：用户安全相关的操作日志，例如登录、删除管理员
     * @param action 操作动作
     * @param error 操作结果
     * @param comment 操作备注
     */
    @Async
    public void logAuthFail(String action, String error, String comment) {
        logAdmin(LOG_TYPE_GENERAL, action, false, error, comment);
    }

    /**
     * 操作成功
     * 订单日志：用户交易相关的操作日志，例如订单发货、退款
     * @param action 操作动作
     */
    @Async
    public void logOrderSucceed(String action) {
        logAdmin(LOG_TYPE_ORDER, action, true, "", "");
    }

    /**
     * 操作成功
     * 订单日志：用户交易相关的操作日志，例如订单发货、退款
     * @param action 操作动作
     * @param result 操作结果
     */
    @Async
    public void logOrderSucceed(String action, String result) {
        logAdmin(LOG_TYPE_ORDER, action, true, result, "");
    }

    /**
     * 操作成功
     * 订单日志：用户交易相关的操作日志，例如订单发货、退款
     * @param action 操作动作
     * @param error 操作结果
     * @param comment 操作备注
     */
    @Async
    public void logOrderSucceed(String action, String error, String comment) {
        logAdmin(LOG_TYPE_GENERAL, action, false, error, comment);
    }

    /**
     * 操作失败
     * 订单日志：用户交易相关的操作日志，例如订单发货、退款
     * @param action 操作动作
     * @param error 操作结果
     */
    @Async
    public void logOrderFail(String action, String error) {
        logAdmin(LOG_TYPE_ORDER, action, false, error, "");
    }

    /**
     * 操作失败
     * 订单日志：用户交易相关的操作日志，例如订单发货、退款
     * @param action 操作动作
     * @param error 操作结果
     * @param comment 操作备注
     */
    @Async
    public void logOrderFail(String action, String error, String comment) {
        logAdmin(LOG_TYPE_GENERAL, action, false, error, comment);
    }

    /**
     * 操作成功
     * 其他日志：如果以上三种不合适，可以选择其他日志，建议是优先级最低的日志级别
     * @param action 操作动作
     */
    @Async
    public void logOtherSucceed(String action) {
        logAdmin(LOG_TYPE_OTHER, action, true, "", "");
    }

    /**
     * 操作成功
     * 其他日志：如果以上三种不合适，可以选择其他日志，建议是优先级最低的日志级别
     * @param action 操作动作
     * @param result 操作结果
     */
    @Async
    public void logOtherSucceed(String action, String result) {
        logAdmin(LOG_TYPE_OTHER, action, true, result, "");
    }

    /**
     * 操作成功
     * 其他日志：如果以上三种不合适，可以选择其他日志，建议是优先级最低的日志级别
     * @param action 操作动作
     * @param error 操作结果
     * @param comment 操作备注
     */
    @Async
    public void logOtherSucceed(String action, String error, String comment) {
        logAdmin(LOG_TYPE_GENERAL, action, false, error, comment);
    }

    /**
     * 操作失败
     * 其他日志：如果以上三种不合适，可以选择其他日志，建议是优先级最低的日志级别
     * @param action 操作动作
     * @param error 操作结果
     */
    @Async
    public void logOtherFail(String action, String error) {
        logAdmin(LOG_TYPE_OTHER, action, false, error, "");
    }

    /**
     * 操作失败
     * 其他日志：如果以上三种不合适，可以选择其他日志，建议是优先级最低的日志级别
     * @param action 操作动作
     * @param error 操作结果
     * @param comment 操作备注
     */
    @Async
    public void logOtherFail(String action, String error, String comment) {
        logAdmin(LOG_TYPE_GENERAL, action, false, error, comment);
    }

    /**
     *
     * @param type  操作分类
     * @param action 操作动作
     * @param succeed 操作状态
     * @param result  操作结果
     * @param comment 补充信息
     */
    public void logAdmin(Short type, String action, Boolean succeed, String result, String comment) {
        LitemallLog log = new LitemallLog();

        try {
            Subject currentUser = SecurityUtils.getSubject();
            if (currentUser != null) {
                LitemallAdmin admin = (LitemallAdmin) currentUser.getPrincipal();
                if (admin != null) {
                    log.setAdmin(admin.getUsername());
                } else {
                    log.setAdmin("匿名用户");
                }
            } else {
                log.setAdmin("匿名用户");
            }
        }catch (Exception e){
            log.setAdmin("匿名用户");
        }

        HttpServletRequest request = GlobalWebUtil.getRequest();
        if (request != null){
            if (!StringUtils.hasText(comment)){
                log.setComment(request.getRequestURI());
            }
            log.setIp(IpUtil.getIpAddr(request));
        }else {
            log.setIp("127.0.0.1");
        }

        log.setType(Integer.valueOf(type));
        log.setAction(action);
        log.setStatus(succeed);
        log.setResult(result);
        if (StringUtils.hasText(comment)){
            log.setComment(comment);
        }
        litemallLogService.add(log);
    }

}
